/**
 * 
 */
package org.jinion.database;

import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jinion.database.connectionPool.ConnectionManager;
import org.jinion.database.impl.DatabaseMySql;

/**
 * @author zhlmmc
 */
public class DatabaseFactory {
	private static final Log log = LogFactory.getLog(DatabaseFactory.class);
	
	/**
	 * 
	 */
	public static final String DEFAULT_CONFIG_FILE = "dbconfig.properties";
	
	private static HashMap<String, AbstractDatabase> databases = new HashMap<String, AbstractDatabase>();
	
	/**
	 * Get properties from the given property file.
	 * 
	 * @param propertyFile
	 * @return
	 * @throws IOException
	 */
	private static Properties getProperties(String propertyFile)
			throws IOException {
		Properties properties = new Properties();
//		System.out.println("Class Loader ID: " + DatabaseFactory.class.getClassLoader());
//		System.out.println("Class Loader ID: " + getClass().getClassLoader());
//		System.out.println("Class Loader ID: " + ClassLoader.getSystemClassLoader());
//		System.out.println("Class Loader ID: " + Thread.currentThread().getContextClassLoader());
//		InputStream stream = DatabaseFactory.class.getClassLoader().getResourceAsStream(propertyFile);
		//ClassLoader.getSystemClassLoader().getResourceAsStream(name);
		
		InputStream stream = ClassLoader.getSystemResourceAsStream(propertyFile);
		if (stream == null) {
			stream = Thread.currentThread().getContextClassLoader().getResourceAsStream(propertyFile);
		}
		properties.load(stream);
		
		return properties;
	}

	/**
	 * Get Database with default database config file "dbconfig.properties".
	 * 
	 * @return instance of IDatabase
	 * @throws IOException
	 * @throws ClassNotFoundException
	 * @throws SQLException
	 */
	public static AbstractDatabase getDatabase() throws IOException,
			ClassNotFoundException, SQLException {
		return getDatabase(DEFAULT_CONFIG_FILE);
	}

	/**
	 * Get Database with the given database config file.
	 * 
	 * @param databaseConfig to databaseConfig file
	 * @return instance of IDatabase
	 * @throws IOException
	 * @throws ClassNotFoundException
	 * @throws SQLException
	 */
	public static AbstractDatabase getDatabase(String databaseConfig)
			throws IOException, ClassNotFoundException, SQLException {
		log.info("Using config file " + databaseConfig);
		
		Properties prop = getProperties(databaseConfig);
		int minCon = Integer.valueOf(prop.getProperty("minimum_connection"));
		int maxCon = Integer.valueOf(prop.getProperty("maximum_connection"));
		
		return getDatabase(prop.getProperty("driver"), prop.getProperty("url"),
				prop.getProperty("user"), prop.getProperty("password"), minCon, maxCon);
	}

	/**
	 * Get the database with the given properties. 
	 * 
	 * @param driver canonical name of database driver
	 * @param url connection url
	 * @param user database user
	 * @param password password for user 
	 * @return instance of IDatabase
	 * @throws ClassNotFoundException
	 * @throws SQLException
	 */
	public static AbstractDatabase getDatabase(String driver, String url,
			String user, String password) throws ClassNotFoundException,
			SQLException {
		return getDatabase(driver, url, user, password, -1, -1);
	}
	
	public static AbstractDatabase getDatabase(String driver, String url,
			String user, String password, int minConnection, int maxConnection) throws ClassNotFoundException,
			SQLException {
		
		log.debug("Database connection info: ");
		log.debug("Driver: " + driver);
		log.debug("URL: " + url);
		log.debug("User: " + user);
		log.debug("Password: " + password);
		log.debug("Minimum Connection: " + minConnection);
		log.debug("Maximum Connection: " + maxConnection);
		
		String key = driver + "_" + url + "_" + user + "_" + password;
		AbstractDatabase database = databases.get(key);
		if (database != null) {
			return database;
		}
		
		ConnectionManager connectionManager = new ConnectionManager(driver, url, user, password, minConnection, maxConnection);
		DatabaseType dbtype = DatabaseType.getDBType(url);
		//TODO: currently, only support mysql
		if (dbtype == DatabaseType.MYSQL) {
			database = new DatabaseMySql(connectionManager);
			databases.put(key, database);
			return database;
		}
		else{
			return null;
		}
	}

	/**
	 * just for test
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		Properties properties = new Properties();
		try {
			properties.load(ClassLoader
					.getSystemResourceAsStream("dbconfig.properties"));
		} catch (IOException e) {
			e.printStackTrace();
		}

		properties.list(System.out);

		// Write properties file.
		// try {
		// properties.store(new FileOutputStream("dbconfig.properties"), null);
		// } catch (IOException e) {
		// }
	}
}
